package im.oen.boot.common.utils;

import im.oen.boot.common.constant.Magic;

import java.io.Serializable;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * <p>描述：模仿Session的工具类</p>
 *
 * <p>创建时间：2021-10-28 11:21</p>
 * <p>更新时间：暂无</p>
 *
 * @author Kevin.Xu
 * @version 1.0
 */
public class SessionUtil {
    static Logger logger = Logger.getLogger(SessionUtil.class.getName());

    private static Map<Serializable, Map<Serializable, Serializable>> SESSION = new ConcurrentHashMap<>();
    private static Map<Serializable, Long> SESSION_TIMEOUT = new ConcurrentHashMap<>();

    static {
        run();
    }

    private static void run() {
        Thread thread = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(Magic.TIME_HALF_SECOND);
                    if (Checker.isEmpty(SessionUtil.SESSION_TIMEOUT)) {
                        return;
                    }

                    long cur = DateUtil.currentTimeMillis();
                    Set<Serializable> keys = SessionUtil.SESSION_TIMEOUT.keySet();
                    for (Serializable key : keys) {
                        Long timeout = SESSION_TIMEOUT.get(key);
                        if (cur > timeout) {
                            SessionUtil.SESSION.remove(key);
                            SessionUtil.SESSION_TIMEOUT.remove(key);
                        }
                    }
                } catch (Exception e) {
                    logger.log(Level.SEVERE, e.getMessage(), e);
                }
            }
        });

        thread.setDaemon(true);
        thread.setName("SESSION-TIMEOUT-Thread");
        thread.start();
    }

    public static synchronized void init(Serializable sessionKey) {
        if (Checker.isEmpty(sessionKey)) {
            return;
        }
        if (SESSION.containsKey(sessionKey)) {
            return;
        }

        updateTimeOut(sessionKey);

        if (SESSION.get(sessionKey) == null) {
            SESSION.put(sessionKey, new ConcurrentHashMap<>());
        }
    }

    private static void updateTimeOut(Serializable sessionKey) {
        if (Checker.isEmpty(sessionKey)) {
            return;
        }
        SESSION_TIMEOUT.put(sessionKey, DateUtil.currentTimeMillis() + Magic.TIME_HALF_HOUR);
    }

    public static <T extends Serializable> T get(Serializable sessionKey, Serializable itemKey) {
        if (Checker.isEmpty(sessionKey) || Checker.isEmpty(itemKey)) {
            return null;
        }
        Map<Serializable, Serializable> map = SESSION.get(sessionKey);
        if (map == null) {
            return null;
        }

        updateTimeOut(sessionKey);
        return (T) map.get(itemKey);
    }

    public static void put(Serializable sessionKey, Serializable itemKey, Serializable itemValue) {
        if (Checker.isEmpty(sessionKey) || Checker.isEmpty(itemKey)) {
            return;
        }

        init(sessionKey);

        Map<Serializable, Serializable> map = SESSION.get(sessionKey);
        if (itemValue == null) {
            map.remove(itemKey);
        } else {
            map.put(itemKey, itemValue);
        }
        SESSION.put(sessionKey, map);
    }
}
